package com.kantboot.util.common;


import lombok.Data;
import lombok.SneakyThrows;
import lombok.experimental.Accessors;
import org.apache.http.HttpEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLContexts;
import org.apache.http.entity.InputStreamEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;

import javax.net.ssl.SSLContext;
import java.io.*;
import java.net.*;
import java.security.KeyStore;

/**
 * 用来获取响应正文
 *
 * @author 方某人
 */
@Data
@Accessors(chain = true)
public class KantBootRequest {

    /**
     * HTML格式
     */
    public final String CONTENT_TYPE_TEXT_HTML = "text/html";

    /**
     * 纯文本格式
     * */
    public final String CONTENT_TYPE_TEXT_PLAIN = "text/plain";

    /**
     * XML格式
     */
    public final String CONTENT_TYPE_TEXT_XML = "text/xml";

    /**
     * gif图片格式
     */
    public final String CONTENT_TYPE_IMAGE_GIF = "image/gif";

    /**
     * jpg图片格式
     */
    public final String CONTENT_TYPE_IMAGE_JPEG = "image/jpeg";

    /**
     * png图片格式
     */
    public final String CONTENT_TYPE_IMAGE_PNG = "image/png";

    /**
     * XHTML格式
     */
    public final String CONTENT_TYPE_APPLICATION_XHTML$XML = "application/xhtml+xml";

    /**
     * XML数据格式
     */
    public final String CONTENT_TYPE_APPLICATION_XML = "application/xml";

    /**
     * Atom XML聚合格式
     */
    public final String CONTENT_TYPE_APPLICATION_ATOM$XML = "application/atom+xml";

    /**
     * JSON数据格式
     */
    public final String CONTENT_TYPE_APPLICATION_JSON = "application/json";

    /**
     * pdf格式
     */
    public final String CONTENT_TYPE_APPLICATION_PDF = "application/pdf";

    /**
     * Word文档格式
     */
    public final String CONTENT_TYPE_APPLICATION_MSWORD = "application/msword";

    /**
     * 二进制流数据（如常见的文件下载）
     */
    public final String CONTENT_TYPE_APPLICATION_OCTET_STREAM = "application/octet-stream";

    /**
     * 编码为key/value格式发送到服务器
     */
    public final String CONTENT_TYPE_APPLICATION_X_FORM_URLENCODED = "application/x-www-form-urlencoded";

    /**
     * 需要在表单中进行文件上传时，就需要使用该格式
     */
    public final String CONTENT_TYPE_MULTIPART_FORM_DATA = "multipart/form-data";

    /**
     * 证书
     */
    private KeyStore keyStore;

    /**
     * 证书类型
     */
    private String keyStoreType = "PKCS12";

    /**
     * 证书文件
     * 可以和KeyStorePath二选一
     */
    private File keyStoreFile;

    /**
     * 证书位置
     * 可以和KeyStoreFile二选一
     */
    private String keyStorePath;

    private String keyStorePassword = null;


    /**
     * 字符集
     */
    private String charsetName="UTF-8";

    /**
     * 请求头
     */
    private String accept = "*/*";

    /**
     * 代表发送端（客户端|服务器）
     * 发送的实体数据的数据类型。
     * 默认格式：application/json
     */
    private String contentType=CONTENT_TYPE_APPLICATION_JSON;

    /**
     * 决定当前的事务完成后，
     * 是否会关闭网络连接。
     * 如果该值是“keep-alive”，
     * 网络连接就是持久的，
     * 不会关闭，
     * 使得对同一个服务器的请求可以继续在该连接上完成。
     */
    private String connection = "Keep-Alive";

    /**
     * User Agent也简称UA
     * 用较为普通的一点来说，
     * 是一种向访问网站提供你所使用的浏览器类型、
     * 操作系统及版本、CPU 类型、浏览器渲染引擎、
     * 浏览器语言、浏览器插件等信息的标识。
     * UA字符串在每次浏览器 HTTP 请求时发送到服务器！
     */
    private String userAgent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1;SV1)";

    /**
     * 发送请求的地址
     */
    private String url="";

    private URLConnection urlConnection;

    @SneakyThrows
    public KantBootRequest(){


        //如果证书文件为空，则判断去通过证书路径添加
        if(this.keyStoreFile==null){
            this.keyStoreFile=new File(this.keyStorePath);
        }

        if(this.keyStoreFile!=null){
            //指定读取证书格式为
            this.keyStore = KeyStore.getInstance(keyStoreType);
        }

        URL reaUrl=new URL(url);

        if(this.accept == null)
            this.urlConnection.setRequestProperty("accept", this.accept);

        if(this.connection == null)
            this.urlConnection.setRequestProperty("connection", this.connection);

        if(this.userAgent == null)
            this.urlConnection.setRequestProperty("user-agent", this.userAgent);
        this.urlConnection.setDoOutput(true);
        this.urlConnection.setDoInput(true);
    }

    @SneakyThrows
    private String sentPostKeyStore(String param){
        //读取本机存放的证书格式
        FileInputStream keyStoreInputStream = new FileInputStream(keyStoreFile);
        if(this.keyStorePassword!=null){
            keyStore.load(keyStoreInputStream,this.keyStorePassword.toCharArray());
        }
        keyStoreInputStream.close();


        //指定TLS版本
        SSLContext sslcontext = SSLContexts.custom()
                .loadKeyMaterial(keyStore, this.keyStorePassword.toCharArray())
                .build();

        //设置httpclient的SSLSocketFactory
        SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(
                sslcontext,
                new String[]{"TLSv1"},
                null,
                SSLConnectionSocketFactory.BROWSER_COMPATIBLE_HOSTNAME_VERIFIER);
        CloseableHttpClient httpclient = HttpClients.custom()
                .setSSLSocketFactory(sslsf)
                .build();
        StringBuffer stringBuffer = new StringBuffer();
        try {
            HttpPost httpPost = new HttpPost(url);
            InputStream is = new ByteArrayInputStream(param.getBytes(charsetName));
            //InputStreamEntity严格是对内容和长度相匹配的。用法和BasicHttpEntity类似
            InputStreamEntity inputStreamEntity = new InputStreamEntity(is, is.available());
            httpPost.setEntity(inputStreamEntity);
            CloseableHttpResponse response = httpclient.execute(httpPost);
            try {
                HttpEntity entity = response.getEntity();
                BufferedReader reader = new BufferedReader(new InputStreamReader(
                        entity.getContent(), charsetName));
                String inputLine;
                while ((inputLine = reader.readLine()) != null) {
                    stringBuffer.append(inputLine);
                }
            } finally {
                response.close();
            }
        } finally {
            httpclient.close();
        }
        return stringBuffer.toString();
    }

    @SneakyThrows
    public String sendPost(String param) {
        if(keyStore!=null){
            sentPostKeyStore(param);
        }
        return null;
    }

    public static void main(String[] args) {
        KantBootRequest kantBootRequest=
                new KantBootRequest()
                .setKeyStorePath("");
        String s = kantBootRequest.sendPost("");
    }

}